;(function () {
  //# Exclude
  type A = number | string | boolean
  type B = number | boolean
  type Foo = Exclude<A, B>
  // 相当于
  type Foo2 = string

  // !原理: T 是 U 的子类型则返回 never 不是则返回 T
  type Exclude1<T, U> = T extends U ? never : T

  /*------------------------- */
  // # Extract
  type A1 = number | string | boolean
  type B1 = number | boolean

  type Foo3 = Extract<A1, B1>
  // 相当于
  type Foo4 = number | boolean

  //作用： 和 Exclude 相反
  // !原理
  type Extract1<T, U> = T extends U ? T : never

  //这里的具体实现其实就是条件类型的分布式特性，即当 T、U 都是联合类型（视为一个集合）时，T 的成员会依次被拿出来进行 extends U ? T1 : T2 的计算，然后将最终的结果再合并成联合类型。
  type AExtractB = Extract<1 | 2 | 3, 1 | 2 | 4> // 1 | 2
  type _AExtractB =
    | (1 extends 1 | 2 | 4 ? 1 : never) // 1
    | (2 extends 1 | 2 | 4 ? 2 : never) // 2
    | (3 extends 1 | 2 | 4 ? 3 : never) // never

  //而差集 Exclude 也是类似，但需要注意的是，差集存在相对的概念，即 A 相对于 B 的差集与 B 相对于 A 的差集并不一定相同，而交集则一定相同。为了便于理解，我们也将差集展开：
  type SetA = 1 | 2 | 3 | 5
  type SetB = 0 | 1 | 2 | 4

  type AExcludeB = Exclude<SetA, SetB> //3 | 5
  type BExcludeA = Exclude<SetB, SetA> //0 | 4

  type _AExcludeB =
    | (1 extends 0 | 1 | 2 | 4 ? never : 1) // never
    | (2 extends 0 | 1 | 2 | 4 ? never : 2) // never
    | (3 extends 0 | 1 | 2 | 4 ? never : 3) // 3
    | (5 extends 0 | 1 | 2 | 4 ? never : 5) // 5

  type _BExcludeA =
    | (0 extends 1 | 2 | 3 | 5 ? never : 0) // 0
    | (1 extends 1 | 2 | 3 | 5 ? never : 1) // never
    | (2 extends 1 | 2 | 3 | 5 ? never : 2) // never
    | (4 extends 1 | 2 | 3 | 5 ? never : 4) // 4
})()
//我们也可以很容易实现并集与补集

type a = 1 | 2 | 3
type b = 2 | 3 | 4
type c = 2
// 并集
export type Concurrence<A, B> = A | B
type test_0 = Concurrence<a, b>

// 交集
export type Intersection<A, B> = A extends B ? A : never
type test_1 = Intersection<a, b>

// 差集(有相对于)
export type Difference<A, B> = A extends B ? never : A
type test_2 = Difference<a, b>

// 补集
export type Complement<A, B extends A> = Difference<A, B>
type test_3 = Complement<a, c>

/*------------------------- */
//# NonNullable 的作用是用来过滤类型中的null及undefined类型。

type NonNullable_0 = NonNullable<string | number | undefined> // string | number

type NonNullable_1 = NonNullable<string[] | null | undefined> // string[]
// !原理:
type NonNullable1<T> = T extends null | undefined ? never : T

//很明显，它的本质就是集合 T 相对于 null | undefined 的差集，因此我们可以用之前的差集来进行实现。
type _NonNullable<T> = Difference<T, null | undefined>
type NonNullable_3 = _NonNullable<string[] | null | undefined> // string[]
